}
g_ptr_array_add (results, ostree_repo_finder_result_new (remote, OSTREE_REPO_FINDER (finder),
- priority, supported_ref_to_checksum,
+ priority, supported_ref_to_checksum, NULL,
GUINT64_FROM_BE (g_variant_get_uint64 (summary_timestamp))));
}
}
continue;
}
- g_ptr_array_add (results, ostree_repo_finder_result_new (remote, finder, priority, supported_ref_to_checksum, 0));
+ g_ptr_array_add (results, ostree_repo_finder_result_new (remote, finder, priority, supported_ref_to_checksum, NULL, 0));
}
g_ptr_array_sort (results, results_compare_cb);
* the code in ostree_repo_pull_from_remotes_async() will be able to
* check it just as quickly as we can here; so don’t duplicate the
* code. */
- g_ptr_array_add (results, ostree_repo_finder_result_new (remote, finder, priority, supported_ref_to_checksum, 0));
+ g_ptr_array_add (results, ostree_repo_finder_result_new (remote, finder, priority, supported_ref_to_checksum, NULL, 0));
}
}
g_hash_table_iter_init (&iter, repo_remote_to_refs);
while (g_hash_table_iter_next (&iter, (gpointer *) &remote, (gpointer *) &supported_ref_to_checksum))
- g_ptr_array_add (results, ostree_repo_finder_result_new (remote, finder, priority, supported_ref_to_checksum, 0));
+ g_ptr_array_add (results, ostree_repo_finder_result_new (remote, finder, priority, supported_ref_to_checksum, NULL, 0));
g_ptr_array_sort (results, results_compare_cb);
* priority
* @ref_to_checksum: (element-type OstreeCollectionRef utf8) (transfer none):
* map of collection–ref pairs to checksums provided by this result
+ * @ref_to_timestamp: (element-type OstreeCollectionRef guint64) (nullable)
+ * (transfer none): map of collection–ref pairs to timestamps provided by this
+ * result
* @summary_last_modified: Unix timestamp (seconds since the epoch, UTC) when
* the summary file for the result was last modified, or `0` if this is unknown
*
OstreeRepoFinder *finder,
gint priority,
GHashTable *ref_to_checksum,
+ GHashTable *ref_to_timestamp,
guint64 summary_last_modified)
{
g_autoptr(OstreeRepoFinderResult) result = NULL;
result->finder = g_object_ref (finder);
result->priority = priority;
result->ref_to_checksum = g_hash_table_ref (ref_to_checksum);
+ result->ref_to_timestamp = ref_to_timestamp != NULL ? g_hash_table_ref (ref_to_timestamp) : NULL;
result->summary_last_modified = summary_last_modified;
return g_steal_pointer (&result);
return ostree_repo_finder_result_new (result->remote, result->finder,
result->priority, result->ref_to_checksum,
- result->summary_last_modified);
+ result->ref_to_timestamp, result->summary_last_modified);
}
/**
/* This may be NULL iff the result is freed half-way through find_remotes_cb()
* in ostree-repo-pull.c, and at no other time. */
g_clear_pointer (&result->ref_to_checksum, g_hash_table_unref);
+ g_clear_pointer (&result->ref_to_timestamp, g_hash_table_unref);
g_object_unref (result->finder);
ostree_remote_unref (result->remote);
g_free (result);
* @ref_to_checksum: (element-type OstreeCollectionRef utf8): map of collection–ref
* pairs to checksums provided by this remote; values may be %NULL to
* indicate this remote doesn’t provide that ref
+ * @ref_to_timestamp: (element-type OstreeCollectionRef guint64) (nullable): map of
+ * collection–ref pairs to timestamps; values may be 0 for various reasons
* @summary_last_modified: Unix timestamp (seconds since the epoch, UTC) when
* the summary file on the remote was last modified, or `0` if unknown
*
* should be available locally, so the details for each checksum can be looked
* up using ostree_repo_load_commit().
*
+ * @ref_to_timestamp provides timestamps for the set of refs in
+ * @ref_to_checksum. The refs are keys (of type #OstreeCollectionRef) and the
+ * values are guint64 pointers with the timestamp associated with the checksum
+ * provided in @ref_to_checksum. @ref_to_timestamp can be %NULL, and when it's
+ * not, the timestamps are zero when any of the following conditions are met:
+ * (1) the override-commit-ids option was used on
+ * ostree_repo_find_remotes_async (2) there was an error in trying to get the
+ * commit metadata (3) the checksum for this ref is %NULL in @ref_to_checksum.
+ *
* Since: 2017.8
*/
typedef struct
gint priority;
GHashTable *ref_to_checksum;
guint64 summary_last_modified;
+ GHashTable *ref_to_timestamp;
/*< private >*/
- gpointer padding[4];
+ gpointer padding[3];
} OstreeRepoFinderResult;
_OSTREE_PUBLIC
OstreeRepoFinder *finder,
gint priority,
GHashTable *ref_to_checksum,
+ GHashTable *ref_to_timestamp,
guint64 summary_last_modified);
_OSTREE_PUBLIC
OstreeRepoFinderResult *ostree_repo_finder_result_dup (OstreeRepoFinderResult *result);
g_autoptr(GHashTable) commit_metadatas = NULL; /* (element-type commit-checksum CommitMetadata) */
g_autoptr(OstreeFetcher) fetcher = NULL;
g_autofree const gchar **ref_to_latest_commit = NULL; /* indexed as @refs; (element-type commit-checksum) */
+ g_autofree guint64 *ref_to_latest_timestamp = NULL; /* indexed as @refs; (element-type commit-timestamp) */
gsize n_refs;
g_autofree char **override_commit_ids = NULL;
g_autoptr(GPtrArray) remotes_to_remove = NULL; /* (element-type OstreeRemote) */
* it’s been moved to @refs_and_remotes_table and is now potentially out
* of date. */
g_clear_pointer (&result->ref_to_checksum, g_hash_table_unref);
+ g_clear_pointer (&result->ref_to_timestamp, g_hash_table_unref);
result->summary_last_modified = summary_last_modified;
}
*
* @ref_to_latest_commit is indexed by @ref_index, and its values are the
* latest checksum for each ref. If override-commit-ids was used,
- * @ref_to_latest_commit won't be initialized or used.*/
+ * @ref_to_latest_commit won't be initialized or used.
+ *
+ * @ref_to_latest_timestamp is also indexed by @ref_index, and its values are
+ * the latest timestamp for each ref, when available.*/
ref_to_latest_commit = g_new0 (const gchar *, n_refs);
+ ref_to_latest_timestamp = g_new0 (guint64, n_refs);
for (i = 0; i < n_refs; i++)
{
* the summary or commit metadata files above. */
ref_to_latest_commit[i] = latest_checksum;
+ if (latest_checksum != NULL && latest_commit_metadata != NULL)
+ ref_to_latest_timestamp[i] = latest_commit_metadata->timestamp;
+ else
+ ref_to_latest_timestamp[i] = 0;
+
if (latest_commit_metadata != NULL)
{
latest_commit_timestamp_str = uint64_secs_to_iso8601 (latest_commit_metadata->timestamp);
{
OstreeRepoFinderResult *result = g_ptr_array_index (results, i);
g_autoptr(GHashTable) validated_ref_to_checksum = NULL; /* (element-type OstreeCollectionRef utf8) */
+ g_autoptr(GHashTable) validated_ref_to_timestamp = NULL; /* (element-type OstreeCollectionRef guint64) */
gsize j, n_latest_refs;
/* Previous error processing this result? */
(GDestroyNotify) ostree_collection_ref_free,
g_free);
+ validated_ref_to_timestamp = g_hash_table_new_full (ostree_collection_ref_hash,
+ ostree_collection_ref_equal,
+ (GDestroyNotify) ostree_collection_ref_free,
+ g_free);
if (override_commit_ids)
{
for (j = 0; refs[j] != NULL; j++)
- g_hash_table_insert (validated_ref_to_checksum, ostree_collection_ref_dup (refs[j]),
- g_strdup (override_commit_ids[j]));
+ {
+ guint64 *timestamp_ptr;
+
+ g_hash_table_insert (validated_ref_to_checksum, ostree_collection_ref_dup (refs[j]),
+ g_strdup (override_commit_ids[j]));
+
+ timestamp_ptr = g_malloc (sizeof (guint64));
+ *timestamp_ptr = 0;
+ g_hash_table_insert (validated_ref_to_timestamp, ostree_collection_ref_dup (refs[j]),
+ timestamp_ptr);
+ }
}
else
{
for (j = 0; refs[j] != NULL; j++)
{
const gchar *latest_commit_for_ref = ref_to_latest_commit[j];
+ guint64 *timestamp_ptr;
if (pointer_table_get (refs_and_remotes_table, j, i) != latest_commit_for_ref)
latest_commit_for_ref = NULL;
g_hash_table_insert (validated_ref_to_checksum, ostree_collection_ref_dup (refs[j]),
g_strdup (latest_commit_for_ref));
+
+ timestamp_ptr = g_malloc (sizeof (guint64));
+ if (latest_commit_for_ref != NULL)
+ *timestamp_ptr = GUINT64_TO_BE (ref_to_latest_timestamp[j]);
+ else
+ *timestamp_ptr = 0;
+ g_hash_table_insert (validated_ref_to_timestamp, ostree_collection_ref_dup (refs[j]),
+ timestamp_ptr);
}
if (n_latest_refs == 0)
}
result->ref_to_checksum = g_steal_pointer (&validated_ref_to_checksum);
+ result->ref_to_timestamp = g_steal_pointer (&validated_ref_to_timestamp);
g_ptr_array_add (final_results, g_steal_pointer (&g_ptr_array_index (results, i)));
}
g_main_context_pop_thread_default (context);
}
+/* Test that using ostree_repo_find_remotes_async() works too.*/
+static void
+test_repo_finder_config_find_remotes (Fixture *fixture,
+ gconstpointer test_data)
+{
+ g_autoptr(OstreeRepoFinder) finder = NULL;
+ g_autoptr(GMainContext) context = NULL;
+ g_autoptr(GAsyncResult) result = NULL;
+ g_auto(OstreeRepoFinderResultv) results = NULL;
+ g_autoptr(GError) error = NULL;
+ gsize i;
+ const OstreeCollectionRef ref0 = { "org.example.Collection0", "exampleos/x86_64/ref0" };
+ const OstreeCollectionRef ref1 = { "org.example.Collection0", "exampleos/x86_64/ref1" };
+ const OstreeCollectionRef ref2 = { "org.example.Collection1", "exampleos/x86_64/ref1" };
+ const OstreeCollectionRef ref3 = { "org.example.Collection1", "exampleos/x86_64/ref2" };
+ const OstreeCollectionRef ref4 = { "org.example.Collection2", "exampleos/x86_64/ref3" };
+ const OstreeCollectionRef * const refs[] = { &ref0, &ref1, &ref2, &ref3, &ref4, NULL };
+ OstreeRepoFinder *finders[2] = {NULL, };
+
+ context = g_main_context_new ();
+ g_main_context_push_thread_default (context);
+
+ /* Put together various ref configuration files. */
+ g_autofree gchar *collection0_uri = assert_create_remote (fixture, "org.example.Collection0",
+ "exampleos/x86_64/ref0",
+ "exampleos/x86_64/ref1",
+ NULL);
+ g_autofree gchar *collection1_uri = assert_create_remote (fixture, "org.example.Collection1",
+ "exampleos/x86_64/ref2",
+ NULL);
+ g_autofree gchar *no_collection_uri = assert_create_remote (fixture, NULL,
+ "exampleos/x86_64/ref3",
+ NULL);
+
+ assert_create_remote_config (fixture->parent_repo, "remote0", collection0_uri, "org.example.Collection0");
+ assert_create_remote_config (fixture->parent_repo, "remote1", collection1_uri, "org.example.Collection1");
+ assert_create_remote_config (fixture->parent_repo, "remote0-copy", collection0_uri, "org.example.Collection0");
+ assert_create_remote_config (fixture->parent_repo, "remote1-bad-copy", collection1_uri, "org.example.NotCollection1");
+ assert_create_remote_config (fixture->parent_repo, "remote2", no_collection_uri, NULL);
+
+ finders[0] = OSTREE_REPO_FINDER (ostree_repo_finder_config_new ());
+
+ /* Resolve the refs. */
+ ostree_repo_find_remotes_async (fixture->parent_repo, refs,
+ NULL, finders,
+ NULL, NULL, result_cb, &result);
+
+ while (result == NULL)
+ g_main_context_iteration (context, TRUE);
+
+ results = ostree_repo_find_remotes_finish (fixture->parent_repo,
+ result, &error);
+ g_assert_no_error (error);
+ g_assert_nonnull (results);
+ g_assert_cmpuint (g_strv_length ((char **) results), ==, 3);
+
+ /* Check that the results are correct: the invalid refs should have been
+ * ignored, and the valid results canonicalised and deduplicated. */
+ for (i = 0; results[i] != NULL; i++)
+ {
+ const char *ref0_checksum, *ref1_checksum, *ref2_checksum, *ref3_checksum;
+ guint64 *ref0_timestamp, *ref1_timestamp, *ref2_timestamp, *ref3_timestamp;
+
+ if (g_strcmp0 (ostree_remote_get_name (results[i]->remote), "remote0") == 0 ||
+ g_strcmp0 (ostree_remote_get_name (results[i]->remote), "remote0-copy") == 0)
+ {
+ g_assert_cmpuint (g_hash_table_size (results[i]->ref_to_checksum), ==, 5);
+
+ ref0_checksum = g_hash_table_lookup (results[i]->ref_to_checksum, &ref0);
+ g_assert_true (ostree_validate_checksum_string (ref0_checksum, NULL));
+
+ ref1_checksum = g_hash_table_lookup (results[i]->ref_to_checksum, &ref1);
+ g_assert_true (ostree_validate_checksum_string (ref1_checksum, NULL));
+
+ ref2_checksum = g_hash_table_lookup (results[i]->ref_to_checksum, &ref2);
+ g_assert (ref2_checksum == NULL);
+
+ g_assert_cmpuint (g_hash_table_size (results[i]->ref_to_timestamp), ==, 5);
+
+ ref0_timestamp = g_hash_table_lookup (results[i]->ref_to_timestamp, &ref0);
+ *ref0_timestamp = GUINT64_FROM_BE (*ref0_timestamp);
+ g_assert_cmpuint (*ref0_timestamp, >, 0);
+
+ ref1_timestamp = g_hash_table_lookup (results[i]->ref_to_timestamp, &ref1);
+ *ref1_timestamp = GUINT64_FROM_BE (*ref1_timestamp);
+ g_assert_cmpuint (*ref1_timestamp, >, 0);
+
+ ref2_timestamp = g_hash_table_lookup (results[i]->ref_to_timestamp, &ref2);
+ *ref2_timestamp = GUINT64_FROM_BE (*ref2_timestamp);
+ g_assert_cmpuint (*ref2_timestamp, ==, 0);
+
+ g_assert_cmpstr (ostree_remote_get_url (results[i]->remote), ==, collection0_uri);
+ }
+ else if (g_strcmp0 (ostree_remote_get_name (results[i]->remote), "remote1") == 0)
+ {
+ g_assert_cmpuint (g_hash_table_size (results[i]->ref_to_checksum), ==, 5);
+
+ ref3_checksum = g_hash_table_lookup (results[i]->ref_to_checksum, &ref3);
+ g_assert_true (ostree_validate_checksum_string (ref3_checksum, NULL));
+
+ ref0_checksum = g_hash_table_lookup (results[i]->ref_to_checksum, &ref0);
+ g_assert (ref0_checksum == NULL);
+
+ g_assert_cmpuint (g_hash_table_size (results[i]->ref_to_timestamp), ==, 5);
+
+ ref3_timestamp = g_hash_table_lookup (results[i]->ref_to_timestamp, &ref3);
+ *ref3_timestamp = GUINT64_FROM_BE (*ref3_timestamp);
+ g_assert_cmpuint (*ref3_timestamp, >, 0);
+
+ ref0_timestamp = g_hash_table_lookup (results[i]->ref_to_timestamp, &ref0);
+ *ref0_timestamp = GUINT64_FROM_BE (*ref0_timestamp);
+ g_assert_cmpuint (*ref0_timestamp, ==, 0);
+
+ g_assert_cmpstr (ostree_remote_get_url (results[i]->remote), ==, collection1_uri);
+ }
+ else
+ {
+ g_assert_not_reached ();
+ }
+ }
+
+ g_main_context_pop_thread_default (context);
+}
+
int main (int argc, char **argv)
{
setlocale (LC_ALL, "");
test_repo_finder_config_no_configs, teardown);
g_test_add ("/repo-finder-config/mixed-configs", Fixture, NULL, setup,
test_repo_finder_config_mixed_configs, teardown);
+ g_test_add ("/repo-finder-config/find-remotes", Fixture, NULL, setup,
+ test_repo_finder_config_find_remotes, teardown);
return g_test_run();
}